package org.misty.redis.web;

import lombok.extern.slf4j.Slf4j;
import org.misty.redis.bloomfilter.BloomFilter;
import org.misty.redis.cache.RedisCache;
import org.misty.redis.locker.RedisLocker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author Misty on 2020-06-01
 */
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    private final static Random rand = new Random();
    @Autowired
    private BloomFilter userFilter;
    @Autowired
    private RedisLocker locker;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedisCache<User> userCache;

    private final List<User> userList = new ArrayList<>();

    @PostConstruct
    private void init() {
        for (int i = 1; i <= 100; i++) {
            User u = new User((long) i, "user" + i);
            userList.add(u);
            userFilter.put(u.getId());
        }
    }

@GetMapping("/{id:\\d+}")
public User getUser(@PathVariable Long id) {
    String sid = "cache:user:" + id;
    randDel(sid);
    return userCache.scope(id)
        .hit(ctx -> (User) redisTemplate.opsForValue().get(sid))
        .miss(ctx -> {
            log.info("查数据库 {}", id);
            sleep(100, TimeUnit.MILLISECONDS);
            User user = userList.stream().filter(u -> u.getId().equals(id)).findFirst().get();
            redisTemplate.opsForValue().set(sid, user);
            return user;
        }).get();
}

    @GetMapping("/test2/{id:\\d+}")
    public User getUser2(@PathVariable Long id) {
        String sid = "cache:user2:" + id;
        randDel(sid);
        return userCache.scope(id)
            .hit(ctx -> (User) redisTemplate.opsForValue().get(sid))
            .miss(ctx -> {
                log.info("查数据库 {}", id);
                sleep(100, TimeUnit.MILLISECONDS);
                User user = userList.stream().filter(u -> u.getId().equals(id)).findFirst().get();
                redisTemplate.opsForValue().set(sid, user);
                return user;
            }).get(500);
    }

    private void randDel(String key) {
        if (rand.nextInt(10000) == 1) {
            log.info("清缓存 {}", key);
            redisTemplate.delete(key);
        }
    }

    public static void sleep(long timeout, TimeUnit unit) {
        try {
            unit.sleep(timeout);
        } catch (InterruptedException ignored) {
        }
    }
}
